package io.gitee.kotle.android.view

import android.content.Context
import android.util.AttributeSet
import android.view.MotionEvent
import android.view.View
import android.view.ViewConfiguration
import androidx.viewpager2.widget.ViewPager2
import androidx.viewpager2.widget.ViewPager2.ORIENTATION_HORIZONTAL
import androidx.viewpager2.widget.ViewPager2.ORIENTATION_VERTICAL
import io.gitee.kotle.android.R
import io.gitee.kotle.android.utils.hadScrollToBottom
import io.gitee.kotle.android.utils.hadScrollToEnd
import io.gitee.kotle.android.utils.hadScrollToStart
import io.gitee.kotle.android.utils.hadScrollToTop
import io.gitee.kotle.android.widget.BaseFrameLayout
import kotlin.math.absoluteValue
import kotlin.math.sign

/**
 * 处理比如竖直的ViewPage2 ，里面嵌套水平的viewPage2，容易误触
 * 同方向处理请 see [NestedScrollableHost]
 */
open class NestedScrollableCompat : BaseFrameLayout {
    private var touchSlop = 0
    private var initialX = 0f
    private var initialY = 0f

    /**
     * 获取父view中的viewPage2
     */
    private val parentViewPager: ViewPager2?
        get() {
            var v: View? = parent as? View
            while (v != null && v !is ViewPager2) {
                v = v.parent as? View
            }
            return v as? ViewPager2
        }


    private var handleChildListener: Function1<MotionEvent, View?>? = null


    constructor(context: Context) : super(context)
    constructor(context: Context, attrs: AttributeSet?) : super(context, attrs) {
        checkAttributeSet(attrs)
    }

    constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : super(
        context,
        attrs,
        defStyleAttr
    ) {
        checkAttributeSet(attrs)
    }

    init {
        touchSlop = ViewConfiguration.get(context).scaledTouchSlop
    }

    private fun checkAttributeSet(attrs: AttributeSet?) {
        attrs ?: return
        context.obtainStyledAttributes(attrs, R.styleable.NestedScrollableCompat).also {
            thresholdRatio =
                it.getFloat(R.styleable.NestedScrollableCompat_thresholdRatio, thresholdRatio)
            val parentOrientation = it.getInt(
                R.styleable.NestedScrollableCompat_parentViewOrientation,
                -1
            )
            if (parentOrientation != -1) {
                parentViewOrientation = parentOrientation
            }
        }.recycle()
    }

    private fun canChildScroll(scrollView: View?): Boolean {
        scrollView ?: return false
        return !(scrollView.hadScrollToStart()
                && scrollView.hadScrollToEnd()
                && scrollView.hadScrollToTop()
                && scrollView.hadScrollToBottom())
    }

    private fun checkChildScroll(scrollView: View?, orientation: Int, delta: Float): Boolean {
        scrollView ?: return false
        val direction = -delta.sign.toInt()
        return when (orientation) {
            ORIENTATION_HORIZONTAL -> (direction < 0 && !scrollView.hadScrollToEnd()) || (direction > 0 && !scrollView.hadScrollToStart())
            ORIENTATION_VERTICAL -> (direction < 0 && !scrollView.hadScrollToBottom()) || (direction > 0 && !scrollView.hadScrollToStart())
            else -> false
        }
    }


    /**
     * 获取需要检查滚动的view
     */
    private fun getCheckScrollChild(event: MotionEvent): View? {
        if (handleChildListener != null) {
            return handleChildListener?.invoke(event)
        }
        //默认选择第一个
        return if (childCount > 0)
            getChildAt(0)
        else
            null
    }

    /**
     * 比例因子，值越小，约不容易触发父view的滚动
     * 0f代表不启用冲突检查功能
     * [thresholdRatio]取值范围[0-1f]
     */
    var thresholdRatio = 0.5f

    /**
     * 如果没有viewPage2，可以手动设置属性值
     */
    var parentViewOrientation: Int? = null

    /**
     * 设置获取冲突的view
     */
    fun setOnGetHandleChildListener(listener: Function1<MotionEvent, View>?) {
        this.handleChildListener = listener
    }

    override fun onInterceptTouchEvent(e: MotionEvent): Boolean {
        handleInterceptTouchEvent(e)
        return super.onInterceptTouchEvent(e)
    }

    private fun handleInterceptTouchEvent(e: MotionEvent) {
        if (thresholdRatio == 0f) {
            return
        }
        val scrollView = getCheckScrollChild(e) ?: return
        // 如果子view不能滚动，就直接返回
        if (!canChildScroll(scrollView)) {
            return
        }
        val orientation = parentViewOrientation ?: parentViewPager?.orientation ?: return
        if (e.action == MotionEvent.ACTION_DOWN) {
            initialX = e.x
            initialY = e.y
            parent.requestDisallowInterceptTouchEvent(true)
        } else if (e.action == MotionEvent.ACTION_MOVE) {
            val dx = e.x - initialX
            val dy = e.y - initialY
            val isVpHorizontal = orientation == ORIENTATION_HORIZONTAL
            // 如果父view是水平滚动的，那么认为此次滑动 x的值就是dx的ratio倍,y不变
            val scaledDx = dx.absoluteValue * if (isVpHorizontal) thresholdRatio else 1f
            // 如果父view是垂直滚动的，那么认为此次滑动 y的值就是dy的ratio倍，x不变
            val scaledDy = dy.absoluteValue * if (isVpHorizontal) 1f else thresholdRatio
            if (scaledDx > touchSlop || scaledDy > touchSlop) {
                if (isVpHorizontal) {
                    parent.requestDisallowInterceptTouchEvent(scaledDy > scaledDx)
                } else {
                    parent.requestDisallowInterceptTouchEvent(scaledDx > scaledDy)
                }
            }
        }
    }
}